package com.fub.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;

import com.fub.guidance.Graph;
import com.fub.guidance.Point;
import com.fub.guidance.Vertex;
import com.fub.positioning.PositioningUtil;

public class Util {

	/**
	 * Returns true, if the level in the building exist.
	 * 
	 * @param level
	 *            the level
	 * @param buildingId
	 *            the id of the building
	 * @return true, if the level in the building exist
	 */
	public static boolean levelExist(int level, String buildingId) {
		for (Vertex node : Graph.getInstance().getNodes()) {
			if (node.getBuildingId().equals(buildingId)) {
				if (node.getPosition().getZ() == level) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Returns a formated representation of the level.
	 * 
	 * @param level
	 *            the level
	 * @return a formated representation of the level
	 */
	public static String getFormatedLevel(int level) {
		String levellabel = "EG";
		if (level > 0) {
			levellabel = level + ". OG";
		} else if (level < 0) {
			levellabel = level + ". UG";
		}
		return levellabel;
	}

	/**
	 * Returns a list of nodes, that meet the criteria.
	 * 
	 * @param input
	 *            the criteria
	 * @param nodes
	 *            all the nodes
	 * @return a list of nodes, that meet the criteria.
	 */
	public static List<Vertex> getMatchingNodes(String input,
			Collection<Vertex> nodes) {
		input = input.trim();
		List<Vertex> matchingNodes = new ArrayList<Vertex>();
		for (Vertex node : nodes) {
			if (((node.getLabel().toLowerCase().indexOf(input.toLowerCase()) != -1))
					&& node.getLabel().length() > 1) {
				matchingNodes.add(node);
				continue;
			}
			for (String key : node.getProperies().keySet()) {
				if (key.equals("imageurl"))
					continue;
				String value = node.getProperies().get(key).toLowerCase();
				if (value.indexOf(input.toLowerCase()) != -1) {
					if (!matchingNodes.contains(node)) {
						matchingNodes.add(node);
					}
				}
			}
		}
		return matchingNodes;
	}

	/**
	 * calculates the zoomed position of a point.
	 * 
	 * @param positionToCalculate
	 *            the point, whose position has to be calculated
	 * @param preferenceDAO
	 *            the preference data access object which describes the zoom
	 *            factor
	 * @return the zoomed position of a point
	 */
	public static Point calculateZoomedPosition(Point positionToCalculate,
			PreferenceDAO preferenceDAO) {
		return new Point(
				(int) (positionToCalculate.getX() * preferenceDAO
						.getZoomFactor()),
				(int) (positionToCalculate.getY() * preferenceDAO
						.getZoomFactor()), positionToCalculate.getZ());
	}

	/**
	 * calculates the zoomed position of a point.
	 * 
	 * @param positionToCalculate
	 *            the point, whose position has to be calculated
	 * @param preferenceDAO
	 *            the preference data access object which describes the zoom
	 *            factor
	 * @return the zoomed position of a point
	 */
	public static Point calculateZoomedPosition(float[] positionToCalculate,
			int etage, PreferenceDAO preferenceDAO) {
		return new Point(
				(int) (positionToCalculate[0] * preferenceDAO.getZoomFactor()),
				(int) (positionToCalculate[1] * preferenceDAO.getZoomFactor()),
				etage);
	}

	/**
	 * Calculates the euclidian distance between two nodes.
	 * 
	 * @param source
	 *            the first node
	 * @param destination
	 *            the second node
	 * @return the euclidian distance between two nodes
	 */
	public static float euclidianDistance(Point source, Point destination) {
		return (float) Math.sqrt(square(source.getX() - destination.getX())
				+ square(source.getY() - destination.getY()));
	};

	/**
	 * Returns the width of a text in pixel.
	 * 
	 * @param text
	 *            the text
	 * @param p
	 *            the paint object
	 * @return the width of a text in pixel
	 */
	public static int getTextWidth(String text, Paint p) {
		Rect r = new Rect();
		p.getTextBounds(text, 0, text.length(), r);
		return r.right - r.left;
	}

	/**
	 * Calculates the length of a path.
	 * 
	 * @param nodes
	 *            the nodes of the path
	 * @return the length of the path
	 */
	public static int calculateShortestPathLength(List<Vertex> nodes) {
		Vertex from = nodes.get(0);
		Vertex to;
		int shortestPathDistanz = 0;
		for (int i = 1; i < nodes.size(); i++) {
			to = nodes.get(i);
			Point fromPoint = new Point(from.getPosition().getX(), from
					.getPosition().getY(), 0);
			Point toPoint = new Point(to.getPosition().getX(), to.getPosition()
					.getY(), 0);
			int weight = Math.round(euclidianDistance(fromPoint, toPoint));
			shortestPathDistanz += weight;
			from = to;
		}
		return shortestPathDistanz;
	}

	/**
	 * Returns true, if the node is a corridor.
	 * 
	 * @param node
	 *            the node
	 * @return true, if the node is a corridor
	 */
	public static boolean isCoridorType(Vertex node) {
		return (node.getType() == Vertex.Type.CORIDOR);
	}

	/**
	 * Returns true, if the node is a room.
	 * 
	 * @param node
	 *            the node
	 * @return true, if the node is a room
	 */
	public static boolean isRoomType(Vertex node) {
		return (node.getType() == Vertex.Type.ROOM);
	}

	/**
	 * Returns true, if the node is an entrance.
	 * 
	 * @param node
	 *            the node
	 * @return true, if the node is an entrance
	 */
	public static boolean isEntranceType(Vertex node) {
		return (node.getType() == Vertex.Type.ENTRANCE);
	}

	/**
	 * Returns true, if the node is a stairs node.
	 * 
	 * @param node
	 *            the node
	 * @return true, if the node is a stairs node
	 */
	public static boolean isStairsType(Vertex node) {
		return (node.getType() == Vertex.Type.STAIRS);
	}

	/**
	 * Returns true, if the node is a lift .
	 * 
	 * @param node
	 *            the node
	 * @return true, if the node is a lift
	 */
	public static boolean isLiftType(Vertex node) {
		return (node.getType() == Vertex.Type.LIFT);
	}

	/**
	 * Returns a list of formated Strings that describe the nodes by label and
	 * level.
	 * 
	 * @param nodes
	 *            the nodes
	 * @return a list of formated Strings that describe the nodes by label and
	 *         level
	 */
	public static String[] getFormatedNodeStrings(List<Vertex> nodes) {
		String[] result = new String[nodes.size()];
		for (int i = 0; i < nodes.size(); i++) {
			Vertex node = nodes.get(i);
			String level = Util.getFormatedLevel(node.getPosition().getZ());
			result[i] = String.format("'%s'  %s", node.getLabel(), level);
		}
		return result;
	}

	/**
	 * Shows a choise dialog.
	 * 
	 * @param dialog
	 *            the dialog
	 * @param title
	 *            the title
	 * @param items
	 *            the items
	 * @param listener
	 *            a callback handler
	 * @param context
	 *            the application context
	 * @return
	 */
	public static Dialog showChoiseDialog(Dialog dialog, String title,
			CharSequence[] items, DialogInterface.OnClickListener listener,
			Context context) {
		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setTitle(title);
		builder.setSingleChoiceItems(items, -1, listener);
		dialog = builder.create();
		dialog.show();
		return dialog;
	}

	/**
	 * Shows a simple alert dialog.
	 * 
	 * @param dialog
	 *            the dialog
	 * @param title
	 *            the title
	 * @param items
	 *            the items
	 * @param listener
	 *            a callback handler
	 * @param context
	 *            the application context
	 * @return
	 */
	public static void showSimpleDialog(String text, Context context) {
		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setTitle(text);
		Dialog dialog = builder.create();
		dialog.show();
	}

	

	public static float[] parseLatitudeAndLongitude(Uri uri) {
		float[] result = new float[2];
		String token[] = uri.toString().split(":");
		String values = token[1].replace(" ", "");
		String latitude = values.split(",")[0];
		String longitude = values.split(",")[1];
		result[0] = Float.parseFloat(latitude);
		result[1] = Float.parseFloat(longitude);
		return result;
	}

	public static boolean isInRadius(float delta, float latitudeFrom,
			float longitudeFrom, float latitudeTo, float longitudeTo) {
		if (Math.abs(latitudeFrom - latitudeTo) < delta
				&& Math.abs(longitudeFrom - longitudeTo) < delta) {
			return true;
		}
		return false;
	}

	private static float square(float n) {
		return n * n;
	}
}
